#ifndef NATIVEPARSER_H
#define NATIVEPARSER_H

#include "nativeparser_base.h"
#include "parser/parser.h"

#include <queue>
#include <map>

#include <wx/event.h>


extern bool s_DebugSmartSense;

extern const int g_EditorActivatedDelay;


class M_Code_Editor;
class EditorBase;
class M_Code_Project;
class cbStyledTextCtrl;
class ClassBrowser;
class Compiler;
class Token;


typedef std::map<M_Code_Project*, wxArrayString> ProjectSearchDirsMap;


struct ccSearchData {
  M_Code_StyledTextCtrl* control;
  wxString          file;
};


enum BrowserViewMode {
  bvmRaw = 0,
  bvmInheritance
};


class NativeParser : public wxEvtHandler, NativeParserBase {
  public:

    NativeParser();


    ~NativeParser();


    ParserBase& GetParser() { return *m_Parser; }


    ParserBase* GetParserByProject( M_Code_Project* project );


    ParserBase* GetParserByFilename( const wxString& filename );


    M_Code_Project* GetProjectByParser( ParserBase* parser );


    M_Code_Project* GetProjectByFilename( const wxString& filename );


    M_Code_Project* GetProjectByEditor( M_Code_Editor* editor );


    M_Code_Project* GetCurrentProject();


    bool IsParserPerWorkspace() const { return m_ParserPerWorkspace; }


    bool Done();


    wxImageList* GetImageList() { return m_ImageList; }


    int GetTokenKindImage( const Token* token );


    wxArrayString GetAllPathsByFilename( const wxString& filename );


    static void AddPaths( wxArrayString& dirs, const wxString& path, bool hasExt );



    ParserBase* CreateParser( M_Code_Project* project );


    bool DeleteParser( M_Code_Project* project );


    bool ReparseFile( M_Code_Project* project, const wxString& filename );


    bool AddFileToParser( M_Code_Project* project, const wxString& filename, ParserBase* parser = nullptr );


    bool RemoveFileFromParser( M_Code_Project* project, const wxString& filename );


    void RereadParserOptions();


    void ReparseCurrentProject();


    void ReparseSelectedProject();


    size_t MarkItemsByAI( ccSearchData* searchData, TokenIdxSet& result, bool reallyUseAI = true,
                          bool isPrefix = true, bool caseSensitive = false, int caretPos = -1 );


    size_t MarkItemsByAI( TokenIdxSet& result, bool reallyUseAI = true, bool isPrefix = true,
                          bool caseSensitive = false, int caretPos = -1 );


    int GetCallTips( wxArrayString& items, int& typedCommas, M_Code_Editor* ed, int pos = wxNOT_FOUND );


    wxArrayString& GetProjectSearchDirs( M_Code_Project* project );



    ClassBrowser* GetClassBrowser() const { return m_ClassBrowser; }


    void CreateClassBrowser();


    void RemoveClassBrowser( bool appShutDown = false );


    void UpdateClassBrowser();

  protected:

    bool DoFullParsing( M_Code_Project* project, ParserBase* parser );


    bool SwitchParser( M_Code_Project* project, ParserBase* parser );


    void SetParser( ParserBase* parser );


    void ClearParsers();


    void RemoveObsoleteParsers();


    std::pair<M_Code_Project*, ParserBase*> GetParserInfoByCurrentEditor();


    void SetTokenKindImage( int kind, const wxBitmap& bitmap, const wxBitmap& mask = wxNullBitmap );
    void SetTokenKindImage( int kind, const wxBitmap& bitmap, const wxColour& maskColour );
    void SetTokenKindImage( int kind, const wxIcon& icon );


    void SetCBViewMode( const BrowserViewMode& mode );

  private:
    friend class CodeCompletion;


    void OnProjectLoadingHook( M_Code_Project* project, TiXmlElement* elem, bool loading );


    size_t AI( TokenIdxSet& result,
               ccSearchData* searchData,
               const wxString& lineText = wxEmptyString,
               bool isPrefix = false,
               bool caseSensitive = false,
               TokenIdxSet* search_scope = 0,
               int caretPos = -1 );


    size_t FindCurrentFunctionToken( ccSearchData* searchData, TokenIdxSet& result, int caretPos = -1 );


    int FindCurrentFunctionStart( ccSearchData* searchData,
                                  wxString*     nameSpace = 0L,
                                  wxString*     procName = 0L,
                                  int*          functionIndex = 0L,
                                  int           caretPos = -1 );


    bool LastAISearchWasGlobal() const { return m_LastAISearchWasGlobal; }


    const wxString& LastAIGlobalSearch() const { return m_LastAIGlobalSearch; }


    bool ParseUsingNamespace( ccSearchData* searchData, TokenIdxSet& search_scope, int caretPos = -1 );


    bool ParseBufferForUsingNamespace( const wxString& buffer, TokenIdxSet& search_scope, bool bufferSkipBlocks = true );


    bool ParseFunctionArguments( ccSearchData* searchData, int caretPos = -1 );


    bool ParseLocalBlock( ccSearchData* searchData, TokenIdxSet& search_scope, int caretPos = -1 );


    bool AddCompilerDirs( M_Code_Project* project, ParserBase* parser );


    bool AddCompilerPredefinedMacros( M_Code_Project* project, ParserBase* parser );


    bool AddCompilerPredefinedMacrosGCC( const wxString& compilerId, M_Code_Project* project, wxString& defs, ParserBase* parser );


    wxString GetCompilerStandardGCC( Compiler* compiler, M_Code_Project* project );


    wxString GetCompilerUsingStandardGCC( const wxArrayString& compilerOptions );


    bool AddCompilerPredefinedMacrosVC( const wxString& compilerId, wxString& defs, ParserBase* parser );


    bool AddProjectDefinedMacros( M_Code_Project* project, ParserBase* parser );


    void AddCompilerIncludeDirsToParser( const Compiler* compiler, ParserBase* parser );


    const wxArrayString& GetGCCCompilerDirs( const wxString &cpp_compiler );


    void AddGCCCompilerDirs( const wxString& masterPath, const wxString& compilerCpp, ParserBase* parser );


    void AddIncludeDirsToParser( const wxArrayString& dirs, const wxString& base, ParserBase* parser );


    void OnParserStart( wxCommandEvent& event );


    void OnParserEnd( wxCommandEvent& event );


    void OnParsingOneByOneTimer( wxTimerEvent& event );


    void OnEditorActivated( EditorBase* editor );


    void OnEditorClosed( EditorBase* editor );


    void InitCCSearchVariables();


    bool AddProjectToParser( M_Code_Project* project );


    bool RemoveProjectFromParser( M_Code_Project* project );

  private:
    typedef std::pair<M_Code_Project*, ParserBase*> ProjectParserPair;
    typedef std::list<ProjectParserPair>       ParserList;


    ParserList                   m_ParserList;

    ParserBase*                  m_TempParser;

    ParserBase*                  m_Parser;


    wxTimer                      m_TimerParsingOneByOne;

    ClassBrowser*                m_ClassBrowser;

    bool                         m_ClassBrowserIsFloating;


    ProjectSearchDirsMap         m_ProjectSearchDirsMap;
    int                          m_HookId;
    wxImageList*                 m_ImageList;

    wxArrayString                m_StandaloneFiles;

    bool                         m_ParserPerWorkspace;

    std::set<M_Code_Project*>         m_ParsedProjects;


    wxString          m_LastAIGlobalSearch;
    bool              m_LastAISearchWasGlobal;
    M_Code_StyledTextCtrl* m_LastControl;
    wxString          m_LastFile;
    int               m_LastFunctionIndex;
    int               m_LastFuncTokenIdx;
    int               m_LastLine;
    wxString          m_LastNamespace;
    wxString          m_LastPROC;
    int               m_LastResult;

};

#endif
